package net.zui.comp;

import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import net.zui.Option;
import net.zui.action.ZKeyAction;
import net.zui.action.ZMouseAction;
import net.zui.entity.ZBaseManager;
import net.zui.enume.MouseState;
import net.zui.error.IdDuplicateException;
import net.zui.inter.IGroup;
import net.zui.util.UComm;
import net.zui.util.UDraw;

/**
   * 组件的基类,x,y,width,height为组件的实际占据区域,事件的触发以此区域为准.<br />
 * outerX,outerY,outerWidth,outerHeight为组件本体加特效总共占据的区域, <br />
   * 重绘以此区域为准, 该区域内所有组件都会重绘. 默认外部区域等于事件区域.<br />
   * 组件一定要加入一个IGroup才有实际用处, 最大的IGroup为ZBaseFrame
 * <br /><br />
 * <b>作者:</b>张天文 <br />
 * <b>日期:</b>2021年4月19日下午2:31:07<br />
 * @date
 */
public abstract class ZBase implements Comparable<ZBase>{
	
	protected int x,y,width,height,index;
	protected int outerX,outerY,outerWidth,outerHeight;
	private int tmpWidth=0,tmpHeight=0;
	protected String id;
	protected IGroup group;
	protected boolean change=true;
	protected BufferedImage img,disabledImg,inImg,image;
	protected boolean visible=true;
	protected boolean able=true;
	protected ZKeyAction innerKey,outerKey;
	protected ZMouseAction innerMouse,outerMouse;
	protected MouseState mouseState = MouseState.mouseOut;

	/**
	 * 最简单的创建Base, 自动生成id
	 * @param frame 组容器
	 * @param width 宽度
	 * @param height 高度
	 */
	public ZBase(IGroup frame, int width,int height) {
		this(null,frame,0,0,width,height);
	}
	
	/**
	   * 创建Base
	 * @param id 组件id, 每个组件都有id, 用于唯一身份
	 * @param frame 组容器
	 * @param x x坐标
	 * @param y y坐标
	 * @param width 宽度
	 * @param height 高度
	 */
	public ZBase(String id,IGroup frame,int x,int y, int width,int height) {
		this(null,frame,x,y,width,height,0);
	}
	
	/**
	   * 创建Base
	 * @param id 组件id, 每个组件都有id, 用于唯一身份
	 * @param frame 组容器
	 * @param x x坐标
	 * @param y y坐标
	 * @param width 宽度
	 * @param height 高度
	 * @param index 层级, 默认为0, 较低的先绘制 
	 */
	public ZBase(String id,IGroup frame,int x,int y, int width,int height,int index) {
		this.group=frame;
		this.id=id==null?ZBaseManager.getId(this.getClass()):id;
		this.x=x;
		this.y=y;
		this.width=width;
		this.height=height;
		this.index=index;
		outerX=x;
		outerY=y;
		outerWidth=width;
		outerHeight=height;
		try {
			frame.getManager().add(this);
		} catch (IdDuplicateException e) {
			e.printStackTrace();
		}
		createImg();
	}
	
	/**
	   * 更新缓存图片,在outerWidth/outerHeight值更改后
	 */
	private void createImg() {
		if(tmpWidth==outerWidth && tmpHeight==outerHeight)return;
		tmpWidth=outerWidth;
		tmpHeight=outerHeight;
		img=new BufferedImage(outerWidth, outerHeight, BufferedImage.TYPE_INT_ARGB);
		disabledImg=new BufferedImage(outerWidth, outerHeight, BufferedImage.TYPE_INT_ARGB);
		inImg=new BufferedImage(outerWidth, outerHeight, BufferedImage.TYPE_INT_ARGB);
	}
	
	/**
	 * change表示该组件是否修改了, 为true的时候重绘. 否则直接绘制缓存图片
	 * @param g 绘制对象
	 */
	public final void update(Graphics2D g) {
		if(able) {
			if(mouseState==MouseState.mouseOut) {
				image=img;
			}else {
				image=inImg;
			}
		}else {
			image=disabledImg;
		}
		if(change) {
			change=false;
			UDraw.Alpha(image);
			Graphics2D graphics = image.createGraphics();
			graphics.setRenderingHints(Option.renderingHints);
			draw(graphics);
			graphics.dispose();
		}
		if(visible)g.drawImage(image, outerX, outerY, null);
	}
	
	/**
	    * 重绘方法, 注意g为缓存图片的绘制对象, 所以起始x/y坐标应该为0, 而不是组件的x/y属性
	 * @param g 绘制对象
	 */
	protected abstract void draw(Graphics2D g);
	
	public IGroup getGroup() {
		return group;
	}

	public int getX() {
		return x;
	}

	public void setX(int x) {
		this.x = x;
		change=true;
	}

	public int getY() {
		return y;
	}

	public void setY(int y) {
		this.y = y;
		change=true;
	}
	
	public void setLocation(int x,int y) {
		this.x = x;
		this.y = y;
		change=true;
	}

	public int getWidth() {
		return width;
	}

	public void setWidth(int width) {
		this.width = width;
		change=true;
	}

	public int getHeight() {
		return height;
	}

	public void setHeight(int height) {
		this.height = height;
		change=true;
	}
	
	public void setSize(int width,int height) {
		this.width = width;
		this.height = height;
		change=true;
	}
	
	public void setBounds(int x,int y,int width,int height) {
		this.x = x;
		this.y = y;
		this.width = width;
		this.height = height;
		change=true;
	}

	public int getIndex() {
		return index;
	}

	public void setIndex(int index) {
		this.index = index;
		group.getManager().setChange();
	}

	public String getId() {
		return id;
	}

	public int getOuterX() {
		return outerX;
	}

	public void setOuterX(int outerX) {
		this.outerX = outerX;
		group.getManager().setChange();
	}

	public int getOuterY() {
		return outerY;
	}

	public void setOuterY(int outerY) {
		this.outerY = outerY;
		group.getManager().setChange();
	}
	
	public void setOuterLocation(int outerX,int outerY) {
		this.outerX = outerX;
		this.outerY = outerY;
		group.getManager().setChange();
	}

	public int getOuterWidth() {
		return outerWidth;
	}

	public void setOuterWidth(int outerWidth) {
		this.outerWidth = outerWidth;
		group.getManager().setChange();
		change=true;
		createImg();
	}

	public int getOuterHeight() {
		return outerHeight;
	}

	public void setOuterHeight(int outerHeight) {
		this.outerHeight = outerHeight;
		group.getManager().setChange();
		change=true;
		createImg();
	}
	
	public void setOuterSize(int outerWidth,int outerHeight) {
		this.outerWidth = outerWidth;
		this.outerHeight = outerHeight;
		group.getManager().setChange();
		change=true;
		createImg();
	}
	
	public void setOuterBounds(int outerX,int outerY,int outerWidth,int outerHeight) {
		this.outerX = outerX;
		this.outerY = outerY;
		this.outerWidth = outerWidth;
		this.outerHeight = outerHeight;
		group.getManager().setChange();
		change=true;
		createImg();
	}
	
	public boolean hasFocus() {
		return false;
	}
	
	public void setFocus() { }
	
	public void lostFocus() { }
	
	@Override
	public int hashCode() {
		String tmp=UComm.arrToStr(id,outerX,outerY,outerWidth,outerHeight,index);
		return tmp.hashCode();
	}
	
	@Override
	public int compareTo(ZBase o) {
		int tmp=index-o.index;
		if(tmp!=0)return tmp;
		tmp=outerX-o.outerX;
		if(tmp!=0)return tmp;
		tmp=outerY-o.outerY;
		if(tmp!=0)return tmp;
		tmp=outerWidth-o.outerWidth;
		if(tmp!=0)return tmp;
		return outerHeight-o.outerHeight;
	}
	
	@Override
	public String toString() {
		return UComm.arrToStr("{",this.getClass(),"}id=",id,";x,y,width,height=",x,",",y,",",width,",",height
			,";outerX,outerY,outerWidth,outerHeight=",outerX,",",outerY,",",outerWidth,",",outerHeight,";index=",index);
	}

	public boolean isVisible() {
		return visible;
	}

	public void setVisible(boolean visible) {
		this.visible = visible;
	}

	public ZKeyAction getOuterKey() {
		return outerKey;
	}

	public void setOuterKey(ZKeyAction outerKey) {
		this.outerKey = outerKey;
	}

	public ZMouseAction getOuterMouse() {
		return outerMouse;
	}

	public void setOuterMouse(ZMouseAction outerMouse) {
		this.outerMouse = outerMouse;
	}

	public MouseState getMouseState() {
		return mouseState;
	}

	public void setMouseState(MouseState mouseState) {
		if(this.mouseState != mouseState && mouseState!=null) {
			this.mouseState = mouseState;
			change=true;
		}
	}

	public boolean getAble() {
		return able;
	}

	public void setAble(boolean able) {
		if(this.able != able) {
			this.able = able;
			change=true;
		}
	}
	
}
